提高代码的质量,有两个路数:1.多测试;2.做代码review;如果能在代码放到外部去之前,做好单元测试,将会节省很多的时间(如果能把事情做好,减少很多处理bug的时间)。
单元测试(unit test)
单元测试能自动化,只是手段,而非目的。避免形式主义。需要持之以恒。想要习惯去做测试还是需要将测试的手段非常熟练,而且易用才能解开。
编写单元测试是对即将实现的算法做复核预演。
测试代码需要在当前包以_test.go结束的文件。
测试函数以Test为名字前缀。
测试命令go test忽略_,.开头的测试文件。
正常编译的时候,会忽略掉测试文件。
main_test.go
1 2 3 4 5 6 7 8 9 10 11 12
| package main import( "testing" ) func add(x,y int) int { return x+y } func TestAdd(t *testing.T){ if add(1,2) != 3 { t.FailNow() } }
|
1 2 3 4 5 6
| $go test -v [cq@localhost test_case]$ go test -v === RUN TestAdd --- PASS: TestAdd (0.00s) PASS ok test_case 0.002s
|
遍历子包测试用例。
testing.T提供的函数
| 方法 |
说明 |
相关 |
| Fail |
失败:继续执行当前测试用例 |
|
| FailNow |
失败:终止当前测试 |
Failed |
| SkipNow |
跳过:停止执行当前测试函数 |
Skip,Skipf,Skipped |
| Log |
输出日志,仅在失败或者-v时候输出 |
Logf |
| Parallel |
与有相同设置的测试函数并行执行(一般会设置两个以上测试用例,否则就无用了) |
|
| Error |
Fail+Log |
Errorf |
| Fatal |
FailNow+Log |
Fatalf |
测试命令常用的参数列表
| 参数 |
说明 |
实例 |
| -args |
命令行参数 |
|
| -v |
输出详细信息verbose |
|
| -parallel |
并行执行多个测试用例 |
|
| -run |
运行指定测试用例,能支持正则表达式 |
|
| -timeout |
全部测试超时将会调用panic默认10ms |
-timeout 1m30s |
| -count |
重复测试次数 |
table driven
使用table将测试参数都准备好,然后推进测试。测试数据和测试逻辑分离,有利于维护。
test main
如果定义了TestMain函数,go test将会执行这个函数,而不是每个具体的测试用例,这样就能把测试的setup/teardown机制用起来。比如测试一些db操作,需要先构造一个db的链接之类的,就可以使用这种模式。
1 2 3
| func TestMain(m *testing.M) { code :=m.Run() os.Exit(code)
|
example
例代码是用于给GoDoc生成帮助文档。对比stdout结果和内部Output注释是否一致来判断是否成功
1 2 3 4 5 6 7
| func ExampleAdd() { fmt.Println(add(1,2)) fmt.Println(add(2,2)) }
|
golang try catch 例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| package main
import ( "fmt" "github.com/sirupsen/logrus" "runtime/debug" )
func safeFunction() { defer func() { if r := recover(); r != nil { logrus.Warnln("Recovered from panic:", r) st := debug.Stack() logrus.Warn("Stack trace:", string(st)) } }()
arr := []int{1, 2, 3} fmt.Println(arr[3]) }
func safeFunctionNilPoint() { defer func() { if r := recover(); r != nil { logrus.Warnln("Recovered from panic:", r) st := debug.Stack() logrus.Warn("Stack trace:", string(st)) } }()
var ptr *int
*ptr = 10 fmt.Println("This line will not be executed") }
func main() { fmt.Println("Starting program")
safeFunction()
safeFunctionNilPoint()
fmt.Println("Program continues to execute after panic") }
|
性能测试
文件名也是使用的 _test.go结束的。函数名称需要使用Benchmark为前缀
1 2 3 4 5 6 7 8 9
| func add(x,y int) int { return x+y } func BenchmarkAdd(b *testing.B) { for i :=0;i<b.N;i++ { _ := add(1,2) } } go test -bench
|
测试中使用断言
1 2 3 4 5 6 7 8 9 10 11
| package main
import ( "testing"
"github.com/stretchr/testify/assert" )
func TestAdd(t *testing.T) { assert.Equal(t, 2+2, 4) }
|
希望忽略掉全部的单元测试,可以使用run=NONE。默认就是并发测试,可以通过-cpu参数设定多个并发限制。
使用 vscode 调试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| { "version": "0.2.0", "configurations": [ { "name": "Attach to Process", "type": "go", "request": "attach", "mode": "local", "dlvFlags": [ "--check-go-version=false" ], "processId": 0 }, { "name": "debug client", "type": "go", "request": "launch", "mode": "auto", "program": "${workspaceFolder}/client", "dlvFlags": [ "--check-go-version=false" ], "args": [ "--env", "local" ] }, { "name": "debug walletserver", "type": "go", "request": "launch", "mode": "debug", "program": "${workspaceFolder}/main.go", "args": [] } ] }
|
组建测试
在 Go 语言中,并没有内置的 TestingSuite,但是您可以使用第三方库来实现测试套件的功能。一个常用的第三方库是 testify,它提供了丰富的断言和辅助函数,同时也支持测试套件的创建和执行。
要使用 testify 创建测试套件,您可以按照以下步骤进行操作:
首先,确保您已经安装了 testify 库。可以使用以下命令来安装它:
1
| go get github.com/stretchr/testify
|
创建一个新的测试文件,并导入 testing 和 github.com/stretchr/testify/suite 包:
1 2 3 4 5 6 7
| package mytests
import ( "testing"
"github.com/stretchr/testify/suite" )
|
创建一个测试套件结构体,并嵌入 suite.Suite:
1 2 3 4
| type MyTestSuite struct { suite.Suite }
|
在测试套件结构体中,可以定义 SetupSuite 和 TearDownSuite 方法,在整个测试套件运行前后进行设置和清理操作。也可以定义其他的测试辅助方法和测试函数。
创建测试函数,并使用 TestSuite 方法创建并运行测试套件:
1 2 3
| func TestMySuite(t *testing.T) { suite.Run(t, new(MyTestSuite)) }
|
在测试套件结构体中,可以定义测试函数,使用 suite 字段来调用断言和辅助函数。例如:
1 2 3 4
| func (suite *MyTestSuite) TestSomething() { suite.Assert().Equal(2, 1+1) }
|
这样,您就可以使用 testify 创建并执行测试套件了。执行测试时,可以使用 go test 命令来运行测试函数,或者使用集成开发环境(IDE)中的测试工具来运行测试套件。
请注意,以上步骤是基于 testify 库的示例,您也可以探索其他第三方库或编写自己的测试套件框架,以满足您的具体需求。